package com.s2.m.btchat;

import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemCommandListener;
import javax.microedition.lcdui.Spacer;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;
import javax.microedition.media.Manager;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;

/**
 * This class creates a conversation window that the user interacts with.
 * It contains a form with a message box in it. To send a message the user
 * can enter his/her message into the message box and use the send command.
 * Received and sent messages are appended above the message box.
 *
 * @author Samik Saha
 */
public class ChatScreen implements CommandListener, ItemCommandListener {

    /**
     * Keep track of all the instances of ChatScreen
     */
    public static Hashtable activeChats = new Hashtable();
    /**
     * Keep the reference to the current midlet's display
     */
    private Display display;
    /**
     * Keep the <code>ChatHandler</code> instance
     */
    private ChatHandler chatHandler = null;
    /**
     * Friends username to be displayed in front the corresponding messages
     */
    private String buddy = "Friend";
    /**
     * Commands for the profile window
     */
    private Command backCommand = new Command("Back", Command.BACK, 0);
    /**
     * a FriendsProfile object to display the friend's profile when requested
     */
    private FriendsProfile friendsProfile = null;
    /**
     * Keep track of the last message sender: <code>BTChat.LOCAL_USER</code> or
     * <code>BTChat.REMOTE_USER</code>
     */
    private int lastMSGSender = -1;
    /**
     * Denotes if the user has closed the chat screen
     */
    private boolean terminated = false;
    /**
     * A Player reference to play sounds
     */
    Player player;
    /**
     * A form is used as the conversation screen, sent and received messages
     * are appended to it
     */
    Form form = new Form("Chat");
    /**
     * Text field for user to enter message
     */
    TextField msgBox = new TextField("", "", 200, TextField.ANY);
    /**
     * Keeps track of the visiblity of this chat screen
     */
    private boolean visible = false;
    /**
     * Commands in the chat window
     */
    private Command viewProfileCommand = new Command("Profile",
            Command.SCREEN, 1);
    private Command sendCommand = new Command("Send", Command.OK, 0);
    private Command closeCommand = new Command("Close", Command.EXIT, 2);
    private Command switchCommand = new Command("Switch to", Command.SCREEN, 3);
    private Command hideCommand = new Command("Hide Chat", Command.SCREEN, 2);

    /**
     * Creates a ChatScreen instance
     * @param chatHandler
     */
    public ChatScreen(ChatHandler chatHandler) {
        this.chatHandler = chatHandler;
        display = Display.getDisplay(BTChat.getInstance());

        buddy = chatHandler.getBuddyName();//get budddy name from Chat Handler

        StringItem s = new StringItem("Connected with", buddy, Item.HYPERLINK);
        s.setDefaultCommand(viewProfileCommand);
        s.setItemCommandListener(this);
        form.append(s);

        msgBox.setDefaultCommand(sendCommand);
        msgBox.setItemCommandListener(this);
        form.append(msgBox);

        int h = form.getHeight() - msgBox.getPreferredHeight() - s.getPreferredHeight();
        int w = form.getWidth();
        Spacer spacer = new Spacer(h, w);
        spacer.setLayout(Item.LAYOUT_NEWLINE_AFTER);
        form.insert(0, spacer);

        form.addCommand(closeCommand);
        form.addCommand(switchCommand);
        form.addCommand(hideCommand);
        form.setCommandListener(this);

        if (Settings.isSoundsEnabled()) {
            initializeSound();
        }
        activeChats.put(buddy, this);
    }

    /**
     * Sets this <code>ChatScreen</code> visible
     */
    public void showUI() {
        visible = true;
        display.setCurrent(form);
        display.setCurrentItem(msgBox);
    }

    /**
     * Checks the visiblity of the current <code>ChatScreen</code>
     * @return true is the ChatScreen is visible. false if it is not currently
     * displayed
     */
    public boolean isVisible() {
        return visible;
    }

    /**
     * Sets the username of the remote user
     * @param buddy the buddy name
     */
    public void setBuddyName(String buddy) {
        this.buddy = buddy;
    }

    /**
     * Implementation of the abstract method <code>commandAction</code> of the
     * <code>CommandListener</code> interface
     * @see CommandListener#commandAction(javax.microedition.lcdui.Command,
     *                                  javax.microedition.lcdui.Displayable)
     * @param c the <code>Command</code> object
     * @param d the <code>Displayable</code> object
     */
    public void commandAction(Command c, Displayable d) {
        if (c == closeCommand && d == form) {
            terminated = true;
            chatHandler.close();
            BTChat.getInstance().showUI();
        } else if (c == switchCommand) {
            new ActiveChats();
        } else if (c == hideCommand) {
            BTChat.getInstance().showUI();
        } else if (c == backCommand && d == friendsProfile) {
            display.setCurrent(form);
        }
    }

    /**
     * Disables the msgBox, so that the user will no longer be able to enter
     * text into it. Also the send command is removed from it
     */
    public void disableSending() {
        msgBox.setConstraints(TextField.UNEDITABLE);
        msgBox.removeCommand(sendCommand);
    }

    /**
     * Appends the message from any user or the system to the conversation
     * window.
     * @param sender Sender of the message - <code>BTChat.LOCAL_USER</code>,
     * <code>BTChat.REMOTE_USER</code> or <code>SYSTEM</code>
     * @param msg The message String
     */
    public void appendMessage(int sender, String msg) {
        if (sender == BTChat.LOCAL_USER) {
            form.insert(form.size() - 1,
                    new StringItem((lastMSGSender == sender) ? "" : "Me",
                    msg + "\n"));

        } else if (sender == BTChat.REMOTE_USER) {
            form.insert(form.size() - 1,
                    new StringItem((lastMSGSender == sender) ? "" : buddy,
                    msg + "\n"));

            if (Settings.isSoundsEnabled()) {
                playSound();
            }
        } else if (sender == BTChat.SYSTEM) {
            form.insert(form.size() - 1,
                    new StringItem("",
                    "------\n" + msg.toUpperCase() + "\n\n"));
        }

        //set msgBox as the current item
        display.setCurrentItem(msgBox);
        //update the last message sender
        lastMSGSender = sender;
    }

    /**
     * Creates a player with the sound. Then the player is realized and
     * prefethed
     */
    private void initializeSound() {
        try {
            InputStream in = getClass().getResourceAsStream("/com/s2/m/res/sound/ding.wav");
            player = Manager.createPlayer(in, "audio/x-wav");
            player.realize();
            player.prefetch();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (MediaException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Plays the message received sound
     */
    private void playSound() {
        try {
            player.start();
        } catch (MediaException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * Checks if the user closed the ChatScreen
     * @return <code>true</code> if user closed the window, <code>false</code>
     * otherwise
     */
    public boolean isTerminated() {
        return terminated;
    }

    /**
     * Implements the <code>commandAction</code> method of the
     * <code>ItemCommandListener</code> interface
     * @see ItemCommandListener#commandAction(javax.microedition.lcdui.Command,
     *                                          javax.microedition.lcdui.Item) 
     * @param c the <code>Command</code> object
     * @param item the <code>Item</code> object
     */
    public void commandAction(Command c, Item item) {
        if (c == viewProfileCommand) {
            showFriendsProfile();
        } else if (c == sendCommand) {
            String message = msgBox.getString();
            //if the message is not empty
            if (!(message.trim().equals(""))) {
                msgBox.setString("");//clear the message box
                chatHandler.sendMessage(message);//send the message
                //append the message to the conversation window
                appendMessage(BTChat.LOCAL_USER, message);
            }
        }
    }

    /**
     * Shows the friend's profile
     */
    private void showFriendsProfile() {
        //create the friends profile using the received values
        friendsProfile = chatHandler.getFriendsProfile();
        friendsProfile.addCommand(backCommand);
        friendsProfile.setCommandListener(this);
        display.setCurrent(friendsProfile);
    }
}

